//-----------------------------------------------------------------------
// <copyright file="VaultUtil.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Ben Lilley</author>
// <email>benjililley@hotmail.com</email>
// <date>2007-07-23</date>
// <summary>Utility for executing Sourcegear Vault command line client.</summary>
//-----------------------------------------------------------------------
namespace Microsoft.Sdc.Tasks.Vault
{
    using System;
    using System.Globalization;
    using System.IO;
    using System.Text;
    using Microsoft.Win32;
    using Microsoft.Sdc.Tasks.Configuration;

    /// <summary>
    /// <para>Utility class to execute Vault command line client.</para>
    /// </summary>
    class VaultUtil
    {
        /// <summary>
        /// Determines download path for get operations, and creates the path if it does not exist.
        /// </summary>
        /// <param name="destinationDirectory">The download path provided by the user, if this is blank the current working directory is use.</param>
        /// <returns>The download path that will be used.</returns>
        public static string CreateGetToPath(string destinationDirectory)
        {
            string getLocation;

            if (!String.IsNullOrEmpty(destinationDirectory))
            {
                getLocation = destinationDirectory;
            }
            else
            {
                getLocation = Path.Combine(Environment.CurrentDirectory, "..");
            }

            if (!Directory.Exists(getLocation))
            {
                Directory.CreateDirectory(getLocation);
            }

            return getLocation;
        }

        /// <summary>
        /// Performs all types of GET operations against the Vault command line client.  The type of GET operation is determined by which command line options are provided.
        /// </summary>
        /// <param name="options">The options used to create the GET command.</param>
        /// <param name="shell">The ShellExecute to use for the GET operation.  This should already have it's FileName property set.</param>
        /// <returns>A Result object containing the success/failure indicator and error message if any.</returns>
        public static Result Get(GetOpts options, ShellExecute shell)
        {
            /**********************************/
            /*** assemble command line opts ***/

            StringBuilder opts = new StringBuilder();

            /**********************************/
            /*** Determine type of GET      ***/

            if (!String.IsNullOrEmpty(options.Label))
            {
                opts.Append("GETLABEL ");
            }
            else
            {
                opts.Append("GET ");
            }

            /***************************************************/
            /*** Construct standard host-connection opts     ***/

            opts.Append(
                String.Format(
                CultureInfo.InvariantCulture,
                " -host {0} -user {1} -password {2} -repository {3} -destpath {4} ",
                options.Server,
                options.Username,
                options.Password,
                options.Repository,
                options.DestinationDirectory));

            /**************************************/
            /*** Set SSL flag if specified      ***/

            if (options.UseSSL)
            {
                opts.Append("-ssl ");
            }

            /***************************************/
            /* set path to item for get operations */

            opts.Append(String.Format(CultureInfo.InvariantCulture, "\"{0}\" ", options.ItemPath));

            /**********************************************/
            /* set label for item if a GETLABEL operation */

            if (!String.IsNullOrEmpty(options.Label))
            {
                opts.Append(String.Format(CultureInfo.InvariantCulture, "\"{0}\" ", options.Label));
            }

            shell.Arguments = opts.ToString();

            /*********************************/
            /*** attempt to execute client ***/

            int returncode = shell.Execute();

            if (returncode == 1)
            {
                throw new TaskException("Vault.ExeNotFound", shell.Filename);
            }

            /********************************************/
            /*** parse and return vault results       ***/

            return ResultReader.ReadResult(shell.StandardOutput);
        }

        /// <summary>
        /// Attemptes to determine the path to vault.exe.  Registry keys for 3.0 and 4.0 are checked, if not present it is assumed vault.exe is on the sytem path or in the working directory.
        /// </summary>
        /// <param name="exeFileName">The name of the client .exe to execute.</param>
        /// <returns>The likely path to the .exe based on registry keys (or just the .exe name if registry keys not found).</returns>
        public static string GetVaultExePath(string exeFileName)
        {
            string vaultClientPath;

            RegistryKey vaultKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\SourceGear\Vault Client");
            if (vaultKey != null)
            {
                // check 3.0 and 4.0 locations
                object regValue = vaultKey.GetValue("InstallDir", null);
                if (regValue == null)
                {
                    regValue = vaultKey.GetValue("SCCServerPath", null);
                }

                if (regValue != null)
                {
                    string vaultIdePath = Convert.ToString(regValue, CultureInfo.InvariantCulture);
                    vaultClientPath = Path.Combine(Path.GetDirectoryName(vaultIdePath), exeFileName);
                }
                else
                {
                    vaultClientPath = exeFileName;
                }
            }
            else
            {
                vaultClientPath = exeFileName;
            }

            return vaultClientPath;
        }
    }

    /// <summary>
    /// Utillity class to store get command options.
    /// </summary>
    class GetOpts
    {
        private string server;
        private string repository;
        private string itemPath;
        private string destinationDirectory;
        private string username;
        private string password;
        private string label;
        private bool useSSL = false;

        /// <summary>
        /// Initializes a new instance of the <see cref="GetOpts"/> class.
        /// </summary>
        public GetOpts()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GetOpts"/> class.
        /// </summary>
        /// <param name="Server">The server.</param>
        /// <param name="Repository">The repository.</param>
        /// <param name="ItemPath">The item path.</param>
        /// <param name="DestinationDirectory">The destination directory.</param>
        /// <param name="Username">The username.</param>
        /// <param name="Password">The password.</param>
        /// <param name="Label">The label.</param>
        /// <param name="UseSSL">if set to <c>true</c> [use SSL].</param>
        public GetOpts(string Server, string Repository, string ItemPath, string DestinationDirectory, string Username, string Password, string Label, bool UseSSL)
        {
            this.server = Server;
            this.repository = Repository;
            this.itemPath = ItemPath;
            this.destinationDirectory = DestinationDirectory;
            this.username = Username;
            this.password = Password;
            this.label = Label;
            this.useSSL = UseSSL;
        }

        /// <summary>
        /// Gets or sets the server.
        /// </summary>
        /// <value>The server.</value>
        public string Server
        {
            get { return (this.server ?? String.Empty); }
            set { this.server = value; }
        }

        /// <summary>
        /// Gets or sets the repository.
        /// </summary>
        /// <value>The repository.</value>
        public string Repository
        {
            get { return (this.repository ?? String.Empty); }
            set { this.repository = value; }
        }

        /// <summary>
        /// Gets or sets the item path.
        /// </summary>
        /// <value>The item path.</value>
        public string ItemPath
        {
            get { return (this.itemPath ?? String.Empty); }
            set { this.itemPath = value; }
        }

        /// <summary>
        /// Gets or sets the destination directory.
        /// </summary>
        /// <value>The destination directory.</value>
        public string DestinationDirectory
        {
            get { return (this.destinationDirectory ?? String.Empty); }
            set { this.destinationDirectory = value; }
        }

        /// <summary>
        /// Gets or sets the username.
        /// </summary>
        /// <value>The username.</value>
        public string Username
        {
            get { return (this.username ?? String.Empty); }
            set { this.username = value; }
        }

        /// <summary>
        /// Gets or sets the password.
        /// </summary>
        /// <value>The password.</value>
        public string Password
        {
            get { return (this.password ?? String.Empty); }
            set { this.password = value; }
        }

        /// <summary>
        /// Gets or sets the label.
        /// </summary>
        /// <value>The label.</value>
        public string Label
        {
            get { return (this.label ?? String.Empty); }
            set { this.label = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether [use SSL].
        /// </summary>
        /// <value><c>true</c> if [use SSL]; otherwise, <c>false</c>.</value>
        public bool UseSSL
        {
            get { return this.useSSL; }
            set { this.useSSL = value; }
        }
    }
}
